package com.saianfu.common.security;

import com.saianfu.common.utils.Base64;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.IvParameterSpec;
import java.io.ByteArrayOutputStream;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;

/**
 */
public class DES {
    /**
     * DES算法密钥
     */
    private static String KEY = "bkFmk$I9KnmYys1y";

    /**
     * 数据加密
     *
     * @param data 要进行加密的数据
     * @return 加密后的数据
     */
    public static String encode(String data) {
        String encryptedData = null;
        try {
            // DES算法要求有一个可信任的随机数
            SecureRandom sr = new SecureRandom();
            DESKeySpec deskey = new DESKeySpec(KEY.getBytes());
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey key = keyFactory.generateSecret(deskey);
            // 加密对象
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, key, sr);
            // 加密，并把字节数组编码成字符
            encryptedData = Base64.encodeBytes(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));

        } catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
        return encryptedData;
    }

    public static String encode(String data, String key) {
        String encryptedData = null;
        try {
            // DES算法要求有一个可信任的随机数
            SecureRandom sr = new SecureRandom();
            DESKeySpec deskey = new DESKeySpec(key.getBytes(StandardCharsets.UTF_8));
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(deskey);
            // 加密对象
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, securekey, sr);
            // 加密，并把字节数组编码成字符
            encryptedData = Base64.encodeBytes(cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)));

        } catch (Exception e) {
            throw new RuntimeException("加密错误，错误信息：", e);
        }
        return encryptedData;
    }

    /**
     * 数据解密
     *
     * @param cryptData 加密数据
     * @return 解密后的数据
     */
    public static String decode(String cryptData) {
        String decryptedData = null;
        try {
            // DES算法要求有一个可信任的随机数
            SecureRandom sr = new SecureRandom();
            DESKeySpec deskey = new DESKeySpec(KEY.getBytes());
            // 创建个密匙工厂，然后用它把DESKeySpec转换成一个SecretKey对象
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey key = keyFactory.generateSecret(deskey);
            // 解密对象
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.DECRYPT_MODE, key, sr);
            // 把字符串解码为字节数组，并解
            decryptedData = new String(cipher.doFinal(Base64.decode(cryptData)), Charset.forName("UTF-8"));
        } catch (Exception e) {
            throw new RuntimeException("解密错误，错误信息：" + e.getMessage(), e);
        }
        return decryptedData;
    }

    public static String decode(String cryptData, String key) {
        String decryptedData = null;
        try {
            // DES算法要求有一个可信任的随机数
            SecureRandom sr = new SecureRandom();
            DESKeySpec deskey = new DESKeySpec(key.getBytes(StandardCharsets.UTF_8));
            // 创建个密匙工厂，然后用它把DESKeySpec转换成一个SecretKey对象
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey securekey = keyFactory.generateSecret(deskey);
            // 解密对象
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.DECRYPT_MODE, securekey, sr);
            // 把字符串解码为字节数组，并解
            decryptedData = new String(cipher.doFinal(Base64.decode(cryptData)), Charset.forName("UTF-8"));
        } catch (Exception e) {
            throw new RuntimeException("解密错误，错误信息：" + e.getMessage(), e);
        }
        return decryptedData;
    }

    public static byte[] decrypt(String cryptData, String key) {
        try {
            int len = cryptData.length() / 2;
            byte[] target = new byte[len];
            int x, i;
            for (x = 0; x < len; x++) {
                i = Integer.parseInt(cryptData.substring(x * 2, ((x + 1) * 2)), 16);
                target[x] = (byte) i;
            }
            key = MD5.md5(key).toUpperCase().substring(0, 8);
            byte[] ivs = key.getBytes("UTF-8");
            if (ivs != null) {

            }
            DESKeySpec desKeySpec = new DESKeySpec(ivs);
            SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
            SecretKey secretKey = keyFactory.generateSecret(desKeySpec);

            IvParameterSpec iv = new IvParameterSpec(ivs);

            Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
            cipher.init(Cipher.DECRYPT_MODE, secretKey, iv);
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            bos.write(cipher.update(target));
            bos.write(cipher.doFinal());
            return bos.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args){
        System.out.println(encode("CQ2f2020"));
        System.out.println(decode("w8z1COIs4iRsbJhcyTkBAw=="));
    }
}